#pragma once

#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string>
#include<unistd.h>
#include<functional>
#include<cstdint>
#include"InetAddr.hpp"
#include"Logger.hpp"

using callback_t = std::function<void(int sockfd , std::string message , InetAddr addr)>;

const static int gdefaultsockfd = -1;
//需要实现初始化 -> socket bind 
//启动服务 -> recvfrom 调用回调方法
//sendto 由回调方法来解决
class ChatServer
{
public:
    ChatServer(uint16_t port , callback_t cb)
    :_sockfd(gdefaultsockfd)
    ,_port(port)
    ,_cb(cb)
    ,_is_running(false)
    {}
    void Init()
    {
        _sockfd = socket(AF_INET ,  SOCK_DGRAM, 0);
        if(_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "创建 socket 失败";
            exit(0);
        }
        LOG(LogLevel::INFO) << "创建 socket 成功: " << _sockfd;

        //将sockfd 与 端口、ip进行绑定
        InetAddr local(_port);
        int n = bind(_sockfd , local.Addr(), local.Length());
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "绑定 socket 失败";
            exit(0);
        }
        LOG(LogLevel::INFO) << "绑定 socket 成功";

    }
    void Start()
    {
        //从文件中读取数据，顺便获取发送方的信息
        //调用回调函数
        _is_running = true;

        //debug
        // std::cout << "Start 内部" << std::endl;
        
        //服务器是一个死循环
        while(_is_running)
        {
            //从文件中华获取数据
            char buffer[1024];
            buffer[0] = 0;
            struct sockaddr_in peer;//输出型参数
            socklen_t len = sizeof(peer);//输入、输出型参数

            std::cout << "recvfrom 前" << std::endl;

            int n = recvfrom(_sockfd , buffer , sizeof(buffer) , 0, (struct sockaddr*)&peer,&len);
            std::cout << "是否调用了recvfrom, n : " << n << std::endl;
            //recvfrom 会返回读取到的数据个数
            if(n > 0)
            {
                //约定还是发送的字符串，那么接收字符串的时候，需要手动加上\0
                buffer[n]=0;
                std::string message = buffer;
                //发送方的信息放在peer 中
                InetAddr clientaddr(peer);
                //debug
                LOG(LogLevel::DEBUG) <<"get a client info# " << clientaddr.Ip() 
                <<"-" << clientaddr.Port() << ":" << buffer;

                _cb(_sockfd , message ,clientaddr);
            }
        }
        _is_running = false;
    }
    ~ChatServer()
    {}
private:
    int _sockfd;
    uint16_t _port;
    callback_t _cb;

    bool _is_running;
};